/****************************************************************************
 Copyright (c) 2012-2012 lijiejun
 Copyright (c) 2010-2012 cocos2d-x.org
 Copyright (c) 2008-2010 Ricardo Quesada
 Copyright (c) 2011      Zynga Inc.
 
 http://www.cocos2d-x.org
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

package org.cocos2d.support.data_support
{
	import org.cocos2d.cocoa.CCObject;
	
	public class ccArray
	{
		public static const CC_INVALID_INDEX : uint = 0xffffffff;
		
		public var num : int, max : int;
		public var arr : CCObject[];
		
		public static function ccArrayNew(capacity : uint) : ccArray
		{
			if (capacity == 0)
				capacity = 1;
			
			var arr : ccArray = new ccArray();
			arr.num = 0;
			arr.arr = new CCObject[capacity];
			arr.max = capacity;
			
			return arr;
		}
		
		public static function ccArrayFree(arr : ccArray) : void
		{
			arr.arr = null;
			arr.num = 0;
		}
		
		public static function ccArrayDoubleCapacity(arr : ccArray) : void
		{
			arr.max *= 2;
			var newArr : CCObject[] = new CCObject[arr.max];
			
			if (newArr == null) throw new Error("ccArrayDoubleCapacity failed. Not enough memory");
			
			// as3 do not have Array.copy method
			for (var i : uint = 0; i < arr.max / 2; i++)
			{
				newArr[i] = arr[i];
			}
			arr.arr = newArr;
		}
		
		public static function ccArrayEnsureExtraCapacity(arr : ccArray, extra : uint) : void
		{
			while (arr.max < arr.num + extra)
			{
				ccArrayDoubleCapacity(arr);
			}
		}
		
		public static function ccArrayShrink(arr : ccArray) : void
		{
			var newSize : uint = 0;
			
			if (arr.max > arr.num && !(arr.num == 0 && arr.max == 1))
			{
				if (arr.num != 0)
				{
					newSize = arr.num;
					arr.max = arr.num;
				}
				else
				{
					newSize = 1;
					arr.max = 1;
				}
				
				var newArr : CCObject[] = new CCObject[newSize];
				
				if (newArr == null) throw new Error("could not reallocate the memory");
				
				for (var i : uint = 0; i < newSize; i++)
				{
					newArr[i] = arr[i];
				}
				
				arr.arr = newArr;
			}
		}
		
		public static function ccArrayGetIndexOfObject(arr : ccArray, object : CCObject) : uint
		{
			for (var i : uint = 0; i < arr.num; i++)
			{
				if (arr.arr[i] == object) return i;
			}
			
			return ccArray.CC_INVALID_INDEX;
		}
		
		public static function ccArrayContainsObject(arr : ccArray, object : CCObject) : Boolean
		{
			return ccArrayGetIndexOfObject(arr, object) != ccArray.CC_INVALID_INDEX;
		}
		
		public static function ccArrayAppendObject(arr : ccArray, object : CCObject) : void
		{
			if (object == null) throw new Error("Invalid parameter!");
			arr.arr[arr.num] = object;
			arr.num++;
		}
		
		public static function ccArrayAppendObjectWithResize(arr : ccArray, object : CCObject) : void
		{
			ccArrayEnsureExtraCapacity(arr, 1);
			ccArrayAppendObject(arr, object);
		}
		
		public static function ccArrayAppendArray(arr : ccArray, plusArr : ccArray)
		{
			for (var i : uint = 0; i < plusArr.num; i++)
			{
				ccArrayAppendObject(arr, plusArr.arr[i]);
			}
		}
		
		public static function ccArrayAppendArrayWithResize(arr : ccArray, plusArr : ccArray) : void
		{
			ccArrayEnsureExtraCapacity(arr, plusArr.num);
			ccArrayAppendArray(arr, plusArr);
		}
		
		public static function ccArrayInsertObjectAtIndex(arr : ccArray, object : CCObject, index : uint) : void
		{
			if (index > arr.num) throw new Error("Invalid index. Out of bounds");
			if (object == null) throw new Error("Invalid parameter!");
			
			ccArrayEnsureExtraCapacity(arr, 1);
			
			var remaining : uint = arr.num - index;
			if (remaining > 0)
			{
				for (var i : uint = arr.num - 1; i >= index; i--)
				{
					arr.arr[i + 1] = arr.arr[i];
				}
			}
			
			arr.arr[index] = object;
			arr.num++;
		}
		
		public static function ccArraySwapObjectsAtIndexes(arr : ccArray, index1 : uint, index2 : uint) : void
		{
			if (index1 >= arr.num) throw new Error("(1) Invalid index. Out of bounds");
			if (index2 >= arr.num) throw new Error("(2) Invalid index. Out of bounds");
			
			var object1 : CCObject = arr.arr[index1];
			
			arr.arr[index1] = arr.arr[index2];
			arr.arr[index2] = object1;
		}
		
		public static function ccArrayRemoveAllObjects(arr : ccArray) : void
		{
			// do not need to do anything in AS3
		}
		
		public static function ccArrayRemoveObjectAtIndex(arr : ccArray, index : uint, bReleaseObj : Boolean = true) : void
		{
			if (arr == null || arr.num <= 0 || index >= arr.num) throw new Error("Invalid index. Out of bounds");
			if (bReleaseObj)
			{
				// release
			}
			arr.num--;
			
			var remaining : uint = arr.num - index;
			if (remaining > 0)
			{
				for (var i : uint = index; i < arr.num - 1; i++)
				{
					arr.arr[i] = arr.arr[i + 1];
				}
			}
		}
		
		public static function ccArrayFastRemoveObjectAtIndex(arr : ccArray, index : uint) : void
		{
			var last : uint = --arr.num;
			arr.arr[index] = arr.arr[last];
		}
		
		public static function ccArrayFastRemoveObject(arr : ccArray, object : CCObject) : void
		{
			var index : uint = ccArrayGetIndexOfObject(arr, object);
			if (index != ccArray.CC_INVALID_INDEX)
			{
				ccArrayFastRemoveObjectAtIndex(arr, index);
			}
		}
		
		public static function ccArrayRemoveObject(arr : ccArray, object : CCObject, bReleaseObj : Boolean = true) : void
		{
			var index : uint = ccArrayGetIndexOfObject(arr, object);
			if (index != ccArray.CC_INVALID_INDEX)
			{
				ccArrayRemoveObjectAtIndex(arr, index, bReleaseObj);
			}
		}
		
		public static function ccArrayRemoveArray(arr : ccArray, minusArr : ccArray) : void
		{
			for (var i : uint = 0; i < minusArr.num; i++)
			{
				ccArrayRemoveObject(arr, minusArr.arr[i]);
			}
		}
		
		public static function ccArrayFullRemoveArray(arr : ccArray, minusArr : ccArray)
		{
			var back : uint = 0;
			var i : uint = 0;
			
			for (i = 0; i < arr.num; i++)
			{
				if (ccArrayContainsObject(minusArr, arr.arr[i]))
				{
					back++;
				}
				else
				{
					arr.arr[i - back] = arr.arr[i];
				}
			}
			
			arr.num -= back;
		}
	}
}
